package king.dominic.jlibrary.util;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.RequiresPermission;
import android.support.v4.app.Fragment;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * Created by king on 2017/1/6.
 * Camera
 */
@SuppressWarnings("unused")
public class Camera {
    private static final int REQUEST_CAPTURE_CAMERA = 1221;
    private static final int REQUEST_CROP = 1222;
    private static final int REQUEST_OPEN_ALBUM = 1223;
    private static final String TAG = "Camera";
    private static Uri mCacheUri;

    private Camera() {
    }

    @RequiresPermission(allOf = {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public static void getImageFromCamera(Activity activity) {
        if (checkExternalStorageState(activity)) {
            activity.startActivityForResult(getImageFromCamera(activity.getApplicationContext()), REQUEST_CAPTURE_CAMERA);
        }
    }

    @RequiresPermission(allOf = {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public static void getImageFromCamera(Fragment fragment) {
        if (checkExternalStorageState(fragment.getContext())) {
            fragment.startActivityForResult(getImageFromCamera(fragment.getContext()), REQUEST_CAPTURE_CAMERA);
        }
    }

    private static Intent getImageFromCamera(Context context) {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        mCacheUri = getCachePhotoUri(context.getApplicationContext());
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mCacheUri);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
//        grantUriPermission(context, intent, mCacheUri);
        grantUriWritePermission(context, intent, mCacheUri);
        return intent;
    }

    private static boolean checkExternalStorageState(Context context) {
        if (TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)) {
            return true;
        }
        Toast.makeText(context.getApplicationContext(), "请确认已经插入SD卡", Toast.LENGTH_LONG).show();
        return false;
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    private static File getCachePhotoFile(Context context) {
        File file = new File(Environment.getExternalStorageDirectory(), context.getPackageName() + "/DKCache/CameraTakePhoto" + System.currentTimeMillis() + ".jpg");
        if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
        return file;
    }

    private static Uri getCachePhotoUri(Context context) {
        return FileProvider.getUriForFile(context, FileUtils.getAuthority(context), getCachePhotoFile(context));
    }

    private static Uri getCachePhotoUri(Context context, File file) {
        return FileProvider.getUriForFile(context, FileUtils.getAuthority(context), file);
    }

    public static void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data, OnActivityResultListener listener) {
        onActivityResult(activity, null, requestCode, resultCode, data, listener);
    }

    public static void clearCache(Context context) {
        FileUtils.deleteFolderFile(getCachePhotoFile(context).getParentFile().getAbsolutePath(), false);
    }

    private static File saveBitmap(Context context, Bitmap bitmap) {
        File file = getCachePhotoFile(context);
        if (bitmap == null || bitmap.isRecycled()) return file;
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null)
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            bitmap.recycle();
        }
        return file;
    }

    public static void onActivityResult(Fragment fragment, CropOption crop, int requestCode, int resultCode, Intent data, OnActivityResultListener listener) {
        onActivityResult(fragment.getActivity(), fragment, crop, requestCode, resultCode, data, listener);
    }

    public static void onActivityResult(Activity activity, CropOption crop, int requestCode, int resultCode, Intent data, OnActivityResultListener listener) {
        onActivityResult(activity, null, crop, requestCode, resultCode, data, listener);
    }

    private static void onActivityResult(Activity activity, Fragment fragment, CropOption crop, int requestCode, int resultCode, Intent data, OnActivityResultListener listener) {
        if (resultCode != Activity.RESULT_OK) return;
        Uri uri;
        switch (requestCode) {
            case REQUEST_OPEN_ALBUM:
                if (data == null) {
                    return;
                }
                uri = data.getData();
                if (uri != null) {
                    mCacheUri = getCachePhotoUri(activity);
                    FileUtils.copy(new File(FileUtils.getRealFilePath(activity, uri)), new File(FileUtils.getRealFilePath(activity, mCacheUri)));
                } else {
                    Bitmap bitmap = data.getParcelableExtra("data");
                    File file = saveBitmap(activity, bitmap);
                    mCacheUri = getCachePhotoUri(activity, file);
                }
            case REQUEST_CAPTURE_CAMERA:
                uri = mCacheUri;
                if (listener != null) {
                    listener.requestCaptureCamera(FileUtils.fileHeader(FileUtils.getRealFilePath(activity, uri)));
                }
                if (crop == null) return;
                crop.setSource(uri);
                revokeUriWritePermission(activity, uri);
                Intent intent = crop.create();
                grantUriReadPermission(activity, intent, crop.getSource());
                grantUriWritePermission(activity, intent, crop.getOutput());
                if (fragment != null)
                    fragment.startActivityForResult(intent, REQUEST_CROP);
                else
                    activity.startActivityForResult(intent, REQUEST_CROP);
                break;
            case REQUEST_CROP:
                revokeUriReadPermission(activity, crop.getSource());
                revokeUriWritePermission(activity, crop.getOutput());

                if (listener != null) {
                    Bitmap bitmap;
                    final String path;
                    if (data != null && (bitmap = data.getParcelableExtra("data")) != null)
                        path = saveBitmap(activity, bitmap).getAbsolutePath();
                    else path = FileUtils.getRealFilePath(activity, mCacheUri);
                    listener.requestCrop(FileUtils.fileHeader(path));
                }
                break;
        }
    }

    @RequiresPermission(allOf = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public static void getImageFromAlbum(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");//相片类型
        activity.startActivityForResult(intent, REQUEST_OPEN_ALBUM);
    }

    @RequiresPermission(allOf = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public static void getImageFromAlbum(Fragment fragment) {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");//相片类型
        fragment.startActivityForResult(intent, REQUEST_OPEN_ALBUM);
    }

    public interface OnActivityResultListener {
        void requestCaptureCamera(String path);

        void requestCrop(String path);
    }

    public static class CropOption {
        private int aspectX = 1;//x比例
        private int aspectY = 1;//y比例
        private boolean returnData = false;//是返回bitmap，否返回uri
        private String outputFormat;//输出流保存格式JPG PNG ...
        private int outputX = 200;//返回的bitmap宽
        private int outputY = 200;//返回的bitmap高
        private Uri output;//输出流保存路径
        private Uri source;//需要截图的图片uri
        private boolean noFaceDetection = true;//是关闭人脸识别功能

        public int getAspectX() {
            return aspectX;
        }

        public void setAspectX(int aspectX) {
            this.aspectX = aspectX;
        }

        public int getAspectY() {
            return aspectY;
        }

        public void setAspectY(int aspectY) {
            this.aspectY = aspectY;
        }

        public boolean isReturnData() {
            return returnData;
        }

        public void setReturnData(boolean returnData) {
            this.returnData = returnData;
        }

        public String getOutputFormat() {
            return outputFormat;
        }

        public void setOutputFormat(String outputFormat) {
            this.outputFormat = outputFormat;
        }

        public int getOutputX() {
            return outputX;
        }

        public void setOutputX(int outputX) {
            this.outputX = outputX;
        }

        public int getOutputY() {
            return outputY;
        }

        public void setOutputY(int outputY) {
            this.outputY = outputY;
        }

        public Uri getOutput() {
            return output == null ? source : output;
        }

        public void setOutput(Uri output) {
            this.output = output;
        }

        public Uri getSource() {
            return source;
        }

        public void setSource(Uri source) {
            this.source = source;
        }

        public boolean isNoFaceDetection() {
            return noFaceDetection;
        }

        public void setNoFaceDetection(boolean noFaceDetection) {
            this.noFaceDetection = noFaceDetection;
        }

        private Intent create() {
            if (source == null)
                throw new NullPointerException("没有设置图片uri");
            Intent intent = new Intent();
            intent.setAction("com.android.camera.action.CROP");
            intent.setDataAndType(source, "image/*");
            intent.putExtra("crop", "true");
            if (aspectX > 0)
                intent.putExtra("aspectX", aspectX);
            if (aspectY > 0)
                intent.putExtra("aspectY", aspectY);
            if (outputX > 0)
                intent.putExtra("outputX", outputX);
            if (outputY > 0)
                intent.putExtra("outputY", outputY);
            intent.putExtra("return-data", returnData);
            if (!returnData) {
                output = output == null ? source : output;
//                if (output == null) {
//                    throw new NullPointerException("Camera$CropOption: output can't be null.");
//                }
                outputFormat = outputFormat == null ? Bitmap.CompressFormat.JPEG.toString() : outputFormat;
//                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, output);
                intent.putExtra("outputFormat", outputFormat);
                intent.putExtra("noFaceDetection", noFaceDetection);
            }
            return intent;
        }
    }

    private static void grantUriReadPermission(Context context, Intent intent, Uri uri) {
        grantUriReadPermission(context, uri, getPackageNames(context, intent));
    }

    private static void grantUriWritePermission(Context context, Intent intent, Uri uri) {
        grantUriWritePermission(context, uri, getPackageNames(context, intent));
    }

    private static void grantUriReadPermission(Context context, Uri uri, String... packageName) {
        grantUriPermission(context, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, packageName);
    }

    private static void grantUriWritePermission(Context context, Uri uri, String... packageName) {
        grantUriPermission(context, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, packageName);
    }

    private static void revokeUriReadPermission(Context context, Uri uri) {
        context.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }

    private static void revokeUriWritePermission(Context context, Uri uri) {
        context.revokeUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    }

    private static String[] getPackageNames(Context context, Intent intent) {
        final PackageManager pm = context.getPackageManager();
        final List<ResolveInfo> resInfoList = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        String[] names = new String[resInfoList.size()];
        int i = 0;
        for (ResolveInfo resolveInfo : resInfoList) {
            names[i++] = resolveInfo.activityInfo.packageName;
        }
        return names;
    }

    private static void grantUriPermission(Context context, Uri uri, int flags, String... packageNames) {
        for (String packageName : packageNames) {
            context.grantUriPermission(packageName, uri, flags);
        }
    }

    private static void grantUriPermission(Context context, Intent intent, Uri uri) {
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resInfoList = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo resolveInfo : resInfoList) {
            String packageName = resolveInfo.activityInfo.packageName;

            context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
    }

    private static void revokeUriPermission(Context context, Uri uri) {
        context.revokeUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
}
